package com.yunshipei.core.ui;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.Toast;

import com.yunshipei.core.R;
import com.yunshipei.core.common.ContentValues;
import com.yunshipei.core.download.YspDownload;
import com.yunshipei.core.download.preview.FilePreview;
import com.yunshipei.core.download.preview.KingGridDocPreview;
import com.yunshipei.core.manager.TabManager;
import com.yunshipei.core.model.AutoLoginModel;
import com.yunshipei.core.model.CookieModel;
import com.yunshipei.core.model.DeveloperAppModel;
import com.yunshipei.core.model.FilePreviewConfig;
import com.yunshipei.core.model.HttpAuthModel;
import com.yunshipei.core.model.NativeEventModel;
import com.yunshipei.core.model.RequestHeaderSSOModel;
import com.yunshipei.core.model.UrlTokenSSOModel;
import com.yunshipei.core.model.WaterMarkConfig;
import com.yunshipei.core.model.XCloudJsModel;
import com.yunshipei.core.model.XDownloadModel;
import com.yunshipei.core.ui.dialog.DocPreviewDialog;
import com.yunshipei.core.ui.view.WaterMarkView;
import com.yunshipei.core.utils.CommonUtils;
import com.yunshipei.core.utils.NetUtils;

import org.chromiun.net.ProxyChangeListener;
import org.json.JSONArray;
import org.json.JSONObject;
import org.xwalk.core.XWalkHttpAuthHandler;
import org.xwalk.core.XWalkView;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;


public class TabFragment extends Fragment implements TabItem.OnTabItemInteractionListener {

    private static final String YSP_PROTOCOL = "enterplorer://";
    public static final int FILE_CHOOSER_RESULT_CODE = 5173;
    public static final int FACE_WEB_VIEW_FILE_CHOOSER_RESULT_CODE = 5174;

    private static final String ARGS_START_URL = "com.enterplorer.start.url";
    private static final String ARGS_APP_MENU = "com.enterplorer.app.menu";
    private static final String ARGS_DEVELOP_APP_MODEL = "com.enterplorer.develop.app.model";
    private static final String ARGS_DEFAULT_SUPPORT_TWO_WEB_VIEW = "com.enterplorer.default.support.2.web.view";
    private static final String ARGS_DEBUG_MODEL = "com.enterplorer.debug.model";
    private static final String ARGS_GLOBAL_RT = "com.enterplorer.global.rt";
    private static final String ARGS_COOKIE_ARRAY_LIST = "com.enterplorer.cookie.array.list";
    private static final String ARGS_ALWAYS_AUTO_LOGIN = "com.enterplorer.aleays.auto.login";
    private static final String ARGS_FILE_PREVIEW_CONFIG = "com.enterplorer.file.preview.config";
    private static final String ARGS_WATER_MARK_CONFIG = "com.enterplorer.water.mark.config";
    private static final String ARGS_WEB_VIEW_TEXT_ZOOM = "com.enterplorer.web.view.text.zoom";
    private static final String ARGS_HTTP_AUTHORIZATIONS = "com.enterplorer.web.view.http.authorizations";
    private static final String ARGS_URL_TOKEN_MODE_SSOS = "com.enterplorer.url.token.ssos";
    private static final String ARGS_REQUEST_HEADERS_MODE_SSOS = "com.enterplorer.request.headers.ssos";

    protected Context mContext;

    private View mRootView;
    private WaterMarkView mWaterMarkView;
    private FrameLayout mWebViewContainer;

    private String mStartUrl = "";
    private String mMenu = "";
    private DeveloperAppModel mDeveloperAppModel;
    private boolean isDefault2WebView;
    private boolean isDebugMode;
    private String mGlobalRTVersion = "";
    private ArrayList<CookieModel> mCookieModels;
    private boolean isAlwaysAutoLogin;
    private FilePreviewConfig mFilePreviewConfig;
    private WaterMarkConfig mWaterMarkConfig;
    private int mTextZoom = 100;
    private ArrayList<HttpAuthModel> mHttpAuthModels;
    private ArrayList<UrlTokenSSOModel> mUrlTokenSSOModels;
    private ArrayList<RequestHeaderSSOModel> mRequestHeaderSSOModels;

    private OnFragmentInteractionListener mTabFragmentInteractionListener;

    private List<XCloudJsModel> xCloudJsModels = new ArrayList<>();
    private String mViewSnapshot = "";
    private boolean isViewDestroy = true;

    private LinkedList<TabItem> mTabItems = new LinkedList<>();
    private long mLastSSOLoginTimeStamp = 0;  //用于记录最后一次单点登录的时间，单点登录10分钟只允许进行一次
    private boolean netStateFlag = true;

    public static TabFragment newInstance(String url) {
        TabFragment tabFragment = new TabFragment();
        Bundle bundle = new Bundle();
        bundle.putString(ARGS_START_URL, url);
        tabFragment.setArguments(bundle);
        return tabFragment;
    }

    //监听网络状态变化的广播,第一次注册会立即执行，所以通过flag标示
    private BroadcastReceiver mNetChangeReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (!TextUtils.isEmpty(action) && action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                TabItem tabItem = getTopTabItem();
                if (tabItem != null) {
                    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
                    if (connectivityManager != null) {
                        NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
                        if (activeNetInfo == null || !activeNetInfo.isConnected() || !activeNetInfo.isAvailable()) {
                            tabItem.netChange(false, false);
                        } else {
                            if (netStateFlag) {
                                netStateFlag = false;
                            } else {
                                int netType = activeNetInfo.getType();
                                if (netType == ConnectivityManager.TYPE_WIFI) {
                                    tabItem.netChange(true, true);
                                } else {
                                    tabItem.netChange(true, false);
                                }
                            }
                        }
                    }
                }
            }
        }
    };

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mTabFragmentInteractionListener = (OnFragmentInteractionListener) context;
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.mContext = getActivity();
        this.netStateFlag = true;
        Bundle bundle = getArguments();
        this.mStartUrl = bundle.getString(ARGS_START_URL);
        this.mMenu = bundle.getString(ARGS_APP_MENU);
        this.mDeveloperAppModel = bundle.getParcelable(ARGS_DEVELOP_APP_MODEL);
        this.isDefault2WebView = bundle.getBoolean(ARGS_DEFAULT_SUPPORT_TWO_WEB_VIEW, true);
        this.isDebugMode = bundle.getBoolean(ARGS_DEBUG_MODEL, false);
        this.mGlobalRTVersion = bundle.getString(ARGS_GLOBAL_RT);
        this.mCookieModels = bundle.getParcelableArrayList(ARGS_COOKIE_ARRAY_LIST);
        this.mWaterMarkConfig = bundle.getParcelable(ARGS_WATER_MARK_CONFIG);
        this.isAlwaysAutoLogin = bundle.getBoolean(ARGS_ALWAYS_AUTO_LOGIN, false);
        this.mFilePreviewConfig = bundle.getParcelable(ARGS_FILE_PREVIEW_CONFIG);
        this.mTextZoom = bundle.getInt(ARGS_WEB_VIEW_TEXT_ZOOM, 100);
        this.mHttpAuthModels = bundle.getParcelableArrayList(ARGS_HTTP_AUTHORIZATIONS);
        this.mUrlTokenSSOModels = bundle.getParcelableArrayList(ARGS_URL_TOKEN_MODE_SSOS);
        this.mRequestHeaderSSOModels = bundle.getParcelableArrayList(ARGS_REQUEST_HEADERS_MODE_SSOS);
        Fragment parentFragment = getParentFragment();
        if (parentFragment != null) {
            if (mTabFragmentInteractionListener == null && parentFragment instanceof OnFragmentInteractionListener) {
                mTabFragmentInteractionListener = (OnFragmentInteractionListener) parentFragment;
            }
        }
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiver(mNetChangeReceiver, filter);


    }

    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container, Bundle savedInstanceState) {
        Log.e("mUrl","fff");
        if (mRootView != null) {
            return mRootView;
        } else {
            mRootView = inflater.inflate(R.layout.fragment_tab, container, false);
            mWaterMarkView = (WaterMarkView) mRootView.findViewById(R.id.water_mark_view);
            initWaterMarkView();
            mWebViewContainer = (FrameLayout) mRootView.findViewById(R.id.fl_web_view_container);
            TabItem tabItem = new TabItem(mContext, mStartUrl, mTextZoom, this);
            mTabItems.add(tabItem);
            tabItem.loadView();
            mWebViewContainer.addView(tabItem.getTabContentView());
            return mRootView;
        }
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        isViewDestroy = false;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        isViewDestroy = true;
    }

    //初始化水印显示方式
    private void initWaterMarkView() {
        if (mWaterMarkConfig != null) {
            mWaterMarkView.setVisibility(View.VISIBLE);
            mWaterMarkView.updateWaterMarkConfig(mWaterMarkConfig);
        } else {
            mWaterMarkView.setVisibility(View.GONE);
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case FILE_CHOOSER_RESULT_CODE:
            case FACE_WEB_VIEW_FILE_CHOOSER_RESULT_CODE:
                openFileChooser(data, requestCode);
                break;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mContext.unregisterReceiver(mNetChangeReceiver);
    }

    public boolean isViewDestroy() {
        return isViewDestroy;
    }

    public void openFileChooser(Intent intent, int requestCode) {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            tabItem.chooseSystemFile(intent, requestCode);
        }
    }

    //================  tab刷新开始  ================
    public void refresh() {
        if (!NetUtils.isNetworkAvailable(mContext)) {
            Toast.makeText(mContext, getString(R.string.net_unavailable), Toast.LENGTH_SHORT).show();
        } else {
            TabItem tabItem = getTopTabItem();
            if (tabItem != null) {
                tabItem.refresh();
            }
        }
    }
    //================  tab刷新结束  =================

    public void forward() {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            tabItem.forward();
        }
    }

    //=========tab中所有的返回逻辑处理  start  ===========
    public void onTabBack() {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            if (tabItem.getEnterWebView() != null) {
                if (tabItem.isAdapter()) {
                    tabItem.loadYspJsBack();
                } else {
                    tabItem.loadWebViewOriginBack();
                }
            } else {
                onCloseWindow(tabItem);
            }
        } else {
            if (mTabFragmentInteractionListener != null) {
                mTabFragmentInteractionListener.backTop();
            }
        }
    }

    //=========tab中所有的返回逻辑处理  end  ===========

    public String getTabAvatarName(boolean reCreate) {
        if (reCreate) {
            TabItem tabItem = getTopTabItem();
            if (tabItem != null) {
                mViewSnapshot = tabItem.getSnapshot();
            }
        }
        return mViewSnapshot;
    }

    /**
     * 显示前一个WebView，隐藏并销毁当前这个webview
     *
     * @param currentTabItem 当前WebView
     */
    private void showPreviousTabItem(final TabItem currentTabItem, boolean isFromCloseWindow) {
        Log.e("isFromCloseWindow",isFromCloseWindow+"");
        mWebViewContainer.removeView(currentTabItem.getTabContentView());
        mTabItems.remove(currentTabItem);
        currentTabItem.release();
        TabItem newTabItem = getTopTabItem();
        if (newTabItem != null) {
            newTabItem.getTabContentView().setVisibility(View.VISIBLE);
            if (mTabFragmentInteractionListener != null) {
                mTabFragmentInteractionListener.backPreWebView(isFromCloseWindow);
            }
        }
    }

    @Override
    public void tabItemBack(TabItem tabItem) {
        if (mTabItems.size() == 0) return;
        if (mTabItems.size() == 1) {
            if (mTabFragmentInteractionListener != null) {
                mTabFragmentInteractionListener.backTop();
            }
        } else {
            showPreviousTabItem(tabItem, false);
        }
    }

    @Override
    public List<XCloudJsModel> getXCloudJsModels() {
        return xCloudJsModels;
    }

    @Override
    public void onCloseWindow(TabItem tabItem) {
        if (mTabItems.size() <= 1) {
            FragmentManager fm = getFragmentManager();
            fm.beginTransaction().remove(this).commit();
            fm.executePendingTransactions();
            TabManager.getInstance().removeView(this);
            if (mTabFragmentInteractionListener != null) {
                mTabFragmentInteractionListener.backTop();
            }
        } else {
            showPreviousTabItem(tabItem, true);
        }
    }

    @Override
    public long optLastSSOTime() {
        if (isAlwaysAutoLogin) {
            return 0;
        }
        return mLastSSOLoginTimeStamp;
    }

    @Override
    public void updateLastSSOTime(long lastSSOTimeStamp) {
        this.mLastSSOLoginTimeStamp = lastSSOTimeStamp;
    }

    @Override
    public void updateProgress(TabItem tabItem, int progress) {
        TabItem lastTabItem = getTopTabItem();
        if (mTabFragmentInteractionListener != null) {
            if (tabItem != null && lastTabItem == tabItem) {
                mTabFragmentInteractionListener.tabProgressChanged(progress);
            } else {
                mTabFragmentInteractionListener.tabProgressChanged(0);
            }
        }
    }

    //XwalkView的文件上传
    @Override
    public void onOpenFileChooser() {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        startActivityForResult(Intent.createChooser(i, getString(R.string.file_chooser)), FILE_CHOOSER_RESULT_CODE);
    }

    //原生WebView文件上传
    @Override
    public boolean onShowFileChooser() {
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.addCategory(Intent.CATEGORY_OPENABLE);
        i.setType("*/*");
        startActivityForResult(Intent.createChooser(i, getString(R.string.file_chooser)), FACE_WEB_VIEW_FILE_CHOOSER_RESULT_CODE);
        return true;
    }

    @Override
    public boolean shouldHandleNoMatcherUrlFromOpenWindow(String url) {
        return mTabFragmentInteractionListener != null && mTabFragmentInteractionListener.shouldHandleNoMatcherUrlFromOpenWindow(url);
    }

    @Override
    public DeveloperAppModel getDeveloperAppModel() {
        return mDeveloperAppModel;
    }

    @Override
    public AutoLoginModel getAutoLoginConfig(String url) {
        if (mTabFragmentInteractionListener != null) {
            return mTabFragmentInteractionListener.getAutoLoginModel(url);
        }
        return null;
    }

    @Override
    public String getUrlToken(String host) {
        if (mUrlTokenSSOModels != null) {
            for (UrlTokenSSOModel urlTokenSSOModel : mUrlTokenSSOModels) {
                String host2 = urlTokenSSOModel.getHost();
                if (!TextUtils.isEmpty(host2) && host2.equals(host)) {
                    return urlTokenSSOModel.getParams();
                }
            }
        }
        return "";
    }

    @Override
    public ArrayList<RequestHeaderSSOModel> getRequestHeaderSSOModels() {
        return mRequestHeaderSSOModels;
    }

    /**
     * 来自于XWalkView自己的下载，该下载由内核调用
     */
    @Override
    public void yspDownload(TabItem tabItem, String fromUrl, XDownloadModel xDownloadModel) {
        if (fromUrl.equals(tabItem.getOriginURL())) {
            if (mFilePreviewConfig == null) {
                onCloseWindow(tabItem);
            } else {
                showPreviousTabItem(tabItem, false);
            }
        }
        currentPageDownload(xDownloadModel);
    }

    @Override
    public boolean showAdapterLoading(String message) {
        return mTabFragmentInteractionListener != null && mTabFragmentInteractionListener.showAdapterLoading(message);
    }

    @Override
    public boolean hideAdapterLoading() {
        return mTabFragmentInteractionListener != null && mTabFragmentInteractionListener.hideAdapterLoading();
    }

    private void currentPageDownload(XDownloadModel xDownloadModel) {
        String proxyIP = "";
        int proxyPort = 0;
        ProxyChangeListener.ProxyConfig proxyConfig = ProxyChangeListener.getProxyConfig();
        if (proxyConfig != null) {
            proxyIP = proxyConfig.mHost;
            proxyPort = proxyConfig.mPort;
        }
        HttpAuthModel httpAuthModel = findHttpAuthorization(xDownloadModel.getUrl());
        if (mFilePreviewConfig != null) {
            Flowable<String> flowable = new FilePreview(xDownloadModel, mFilePreviewConfig, proxyIP, proxyPort, httpAuthModel).start();
            subscribeFilePreview(flowable);
        } else {
            YspDownload.startDownload(mContext, xDownloadModel, proxyIP, proxyPort, httpAuthModel);
        }
    }

    //开启新WebView打开适配,替换当前的WebView，以便于点击返回的时候可以返回到上一级
    @Override
    public void openNewWebViewLoadUrl(String url) {
        if (!NetUtils.isNetworkAvailable(mContext)) {
            Toast.makeText(mContext, getString(R.string.net_unavailable), Toast.LENGTH_SHORT).show();
        } else {
            TabItem tabItems = getTopTabItem();
            if (tabItems != null) {
                tabItems.getTabContentView().setVisibility(View.INVISIBLE);
            }
            TabItem nextTabItem = new TabItem(mContext, url, mTextZoom, this);
            if (mStartUrl.startsWith(YSP_PROTOCOL)) {
                nextTabItem.setParentWebViewScope(CommonUtils.getHost(mStartUrl));
            }
            nextTabItem.loadView();
            mTabItems.add(nextTabItem);
            mWebViewContainer.addView(nextTabItem.getTabContentView());
        }
    }

    @Override
    public void onWebViewUrlChanged(String url, TabItem tabItem) {
        if (mTabFragmentInteractionListener != null) {
            mTabFragmentInteractionListener.webViewUrlChanged(url);
        }
    }

    /**
     * 适配调用，可能是下载（post），可能是金格文件的处理
     */
    @Override
    public void onOpenDocumentFile(String data) {
        JSONObject dataJSON = null;
        try {
            dataJSON = new JSONObject(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (dataJSON != null) {
            String extraInfo = dataJSON.optString("extInfo");
            boolean kingGrid = !TextUtils.isEmpty(extraInfo) && ("JINGE".equals(extraInfo) || "ZHONGJIAO".equals(extraInfo));
            //判断是否是金格文档
            if (kingGrid) {
                if (mFilePreviewConfig != null) {
                    String url = dataJSON.optString("downloadUrl");
                    kingGridDocPreview(url, data);
                } else {
                    if (mTabFragmentInteractionListener != null) {
                        mTabFragmentInteractionListener.kingGridFile(data);
                    }
                }
            } else {
                openDocumentDownload(dataJSON);
            }
        }
    }

    @Override
    public String getMenu() {
        return mMenu;
    }

    @Override
    public boolean isOpen2WebView() {
        return isDefault2WebView;
    }

    @Override
    public boolean isDebugMode() {
        return isDebugMode;
    }

    @Override
    public boolean onEnterHttpAuthRequest(XWalkView view, XWalkHttpAuthHandler handler, String host, String realm) {
        if (mHttpAuthModels != null) {
            for (HttpAuthModel httpAuthModel : mHttpAuthModels) {
                if (host.equals(httpAuthModel.getHost())) {
                    if (handler.isFirstAttempt()) {
                        handler.proceed(httpAuthModel.getUserName(), httpAuthModel.getPassword());
                        return true;
                    }
                    break;
                }
            }
        }
        return mTabFragmentInteractionListener != null && mTabFragmentInteractionListener.onReceivedHttpAuthRequest(view, handler, host, realm);
    }

    @Override
    public String getGlobalRTVersion() {
        return mGlobalRTVersion;
    }

    @Override
    public ArrayList<CookieModel> getCookieModels() {
        return mCookieModels;
    }

    @Override
    public boolean shouldWebLoadUrlSelf(XWalkView view, String url) {
        return mTabFragmentInteractionListener != null && mTabFragmentInteractionListener.shouldInterceptWebViewShouldOverrideUrlLoadingMethod(view, url);
    }

    @Override
    public void postNativeEvent(NativeEventModel nativeEventModel) {
        TabItem tabItem = mTabItems.get(0);
        if (tabItem != null) {
            tabItem.loadWebViewAction(nativeEventModel.getData());
        }
    }

    public String getStartURL() {
        return mStartUrl;
    }

    public void release() {
        for (TabItem tabItem : mTabItems) {
            tabItem.release();
        }
        mTabItems.clear();
        if (mWebViewContainer != null) {
            mWebViewContainer.removeAllViews();
        }
        if (mWaterMarkView != null) {
            SurfaceHolder holder = mWaterMarkView.getHolder();
            if (holder != null) {
                Surface surface = holder.getSurface();
                if (surface != null) {
                    surface.release();
                }
            }
        }
    }

    /**
     * 当前适配PC版的url页面
     */
    public void openPCPage() {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            tabItem.loadPCUrl();
        }
    }

    //获取TabFragment当前WebView有效的url，如果是enterplorer协议或者适配的应用，则返回地址栏的url
    public String getURLFromAddrBar() {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            return tabItem.getWebViewURL();
        }
        return "";
    }

    //当前应用是适配包中的资源
    public boolean isCurrentYspWebApp() {
        TabItem tabItem = getTopTabItem();
        return tabItem != null && tabItem.isYspWebApp();
    }

    //只有适配的单子详情页面才支持打开电脑版
    public boolean isCurrentPageSupportOpenPC() {
        TabItem tabItem = getTopTabItem();
        return tabItem != null && tabItem.isAdapter();
    }

    //设置需要注入WebView的对象，方便js调用原生方法
    public void addJavascriptInterface(Object object, String name) {
        xCloudJsModels.add(new XCloudJsModel(object, name));
    }

    public TabItem getTopTabItem() {
        return mTabItems.peekLast();
    }

    public boolean isTopWebViewAdapter() {
        boolean isAdapter = false;
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            isAdapter = tabItem.isAdapter();
        }
        return isAdapter;
    }

    public String getTopItemWebViewTitle() {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            return tabItem.getEnterWebView().getTitle();
        }
        return "";
    }

    public String getTopItemOriginUrl() {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            return tabItem.getOriginURL();
        }
        return "";
    }

    public void loadJSApi(String jsContent) {
        TabItem tabItem = getTopTabItem();
        if (tabItem != null) {
            tabItem.loadJsApi(jsContent);
        }
    }

    public void changeWebDefaultFontSize(int size) {
        Bundle bundle = getArguments();
        if (bundle != null) {
            bundle.putInt(ARGS_WEB_VIEW_TEXT_ZOOM, size);
        }
        mTextZoom = size;
        for (TabItem tabItem : mTabItems) {
            tabItem.setDefaultFontSize(size);
        }
    }

    public void updateMenu(String menu) {
        Bundle bundle = getArguments();
        if (bundle != null) {
            bundle.putString(ARGS_APP_MENU, menu);
        }
    }

    /**
     * 当用户没有填写ad的用户名密码时，xwalkview会默认弹出窗口让你填写当前url需要认证的用户名密码，
     * 填写后需要调用该方法更新内容。
     *
     * @param host     认证系统的host
     * @param userName 认证的用户名
     * @param password 认证的密码
     */
    public void notifyHttpAuthDataChanged(String host, String userName, String password) {
        if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(userName) && !TextUtils.isEmpty(password)) {
            HttpAuthModel httpAuthModel = null;
            if (mHttpAuthModels == null) {
                mHttpAuthModels = new ArrayList<>();
            } else {
                for (HttpAuthModel model : mHttpAuthModels) {
                    if (model.getHost().equals(host)) {
                        httpAuthModel = model;
                        break;
                    }
                }
            }
            if (httpAuthModel != null) {
                mHttpAuthModels.remove(httpAuthModel);
            }
            mHttpAuthModels.add(new HttpAuthModel(host, userName, password));
            Bundle bundle = getArguments();
            if (bundle != null) {
                bundle.putParcelableArrayList(ARGS_HTTP_AUTHORIZATIONS, mHttpAuthModels);
            }
        }
    }

    public void loadAdapterAction(String adapterAction) {
        int size = mTabItems.size();
        if (size > 1) {
            for (int i = size - 1; i > 0; i--) {
                final TabItem tabItem = mTabItems.get(i);
                mWebViewContainer.removeView(tabItem.getTabContentView());
                mTabItems.remove(tabItem);
                mWebViewContainer.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //此处延迟200毫秒销毁WebView是防止调用不存在的js方法，WebView已经销毁，但WebView里面还在执行而导致程序crash
                        tabItem.release();
                    }
                }, 200);
            }
        }
        if (mTabItems.size() == 1) {
            TabItem tabItem = mTabItems.get(0);
            View view = tabItem.getTabContentView();
            if (view.getVisibility() == View.INVISIBLE) {
                view.setVisibility(View.VISIBLE);
            }
            tabItem.loadWebViewAction(adapterAction);
        }
    }

    private Disposable mDocPreviewDisposable;

    private HttpAuthModel findHttpAuthorization(String url) {
        HttpAuthModel httpAuthModel = null;
        if (mHttpAuthModels != null) {
            String host = CommonUtils.getHost(url);
            if (!TextUtils.isEmpty(host)) {
                for (HttpAuthModel authModel : mHttpAuthModels) {
                    if (host.equals(authModel.getHost())) {
                        httpAuthModel = authModel;
                        break;
                    }
                }
            }
        }
        return httpAuthModel;
    }

    /**
     * 金格的文档预览
     */
    private void kingGridDocPreview(String url, String data) {
        String proxyIP = "";
        int proxyPort = 0;
        ProxyChangeListener.ProxyConfig proxyConfig = ProxyChangeListener.getProxyConfig();
        if (proxyConfig != null) {
            proxyIP = proxyConfig.mHost;
            proxyPort = proxyConfig.mPort;
        }
        Flowable<String> flowable = new KingGridDocPreview(mContext, mFilePreviewConfig, data, proxyIP, proxyPort, findHttpAuthorization(url)).start();
        subscribeFilePreview(flowable);
    }

    /**
     * openDocument方法的下载，该方法中的内容一定不是金格，但是需要知道是下载还是预览
     */
    private void openDocumentDownload(JSONObject jsonObject) {
        String downloadURL = jsonObject.optString("downloadUrl");
        String fileName = jsonObject.optString("docName") + jsonObject.optString("docType", "");
        String httpMethod = jsonObject.optString("downloadType", "GET");
        String cookie = "";
        JSONObject headerObjs = jsonObject.optJSONObject("downloadHttpHeaders");
        if (headerObjs != null) {
            cookie = headerObjs.optString("cookie", "");
        }
        JSONArray params = jsonObject.optJSONArray("downloadHttpParams");
        String requestParams = "";
        if (params != null) {
            requestParams = params.toString();
        }
        XDownloadModel xDownloadModel = new XDownloadModel(downloadURL, httpMethod, cookie, fileName, requestParams);
        currentPageDownload(xDownloadModel);
    }

    //文档预览结果回调
    private void subscribeFilePreview(Flowable<String> previewFlowable) {
        final DocPreviewDialog docPreviewDialog = new DocPreviewDialog(mContext);
        docPreviewDialog.setOnCancelPreviewListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                docPreviewDialog.dismiss();
                if (mDocPreviewDisposable != null && !mDocPreviewDisposable.isDisposed()) {
                    mDocPreviewDisposable.dispose();
                }
            }
        });
        docPreviewDialog.show();
        mDocPreviewDisposable = previewFlowable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<String>() {
            @Override
            public void accept(String url) throws Exception {
                if (!url.contains(ContentValues.YSP_PARAM_FORCE_PC)) {
                    Uri uri = Uri.parse(url);
                    if (uri != null) {
                        Set<String> sets = uri.getQueryParameterNames();
                        if (sets != null && sets.size() > 0) {
                            url += "&" + ContentValues.YSP_PARAM_FORCE_PC;
                        } else {
                            url += "?" + ContentValues.YSP_PARAM_FORCE_PC;
                        }
                    }
                }
                docPreviewDialog.dismiss();
                if (mFilePreviewConfig.isExternalPreview() && mTabFragmentInteractionListener != null) {
                    mTabFragmentInteractionListener.filePreviewConvertResult(url);
                } else {
                    openNewWebViewLoadUrl(url);
                }
            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {
                docPreviewDialog.dismiss();
                Toast.makeText(mContext, throwable.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    public interface OnFragmentInteractionListener {
        /**
         * 当前WebView已经返回到最顶部，不能再继续返回了
         */
        void backTop();

        /**
         * WebView地址栏地址变化
         *
         * @param url 加载的url
         */
        void webViewUrlChanged(String url);

        /**
         * 金格文件下载
         */
        void kingGridFile(String data);

        /**
         * http请求认证接口
         *
         * @param view    当前WebView
         * @param handler 处理器
         * @param host    url host
         * @return true：自己处理   false：不处理，系统会弹出自己的UI
         */
        boolean onReceivedHttpAuthRequest(XWalkView view, XWalkHttpAuthHandler handler, String host, String realm);

        /**
         * tab里面WebView进度的变化，如果有多个tab，则会返回最顶层的WebView的进度
         */
        void tabProgressChanged(int progress);

        /**
         * 适配页面内部返回（Tab内部返回），原生页面TabItem的切换，参数为是否是closeWindow的返回
         */
        void backPreWebView(boolean isFromCloseWindow);

        /**
         * OpenWindow方法会返回一个url，如果没有_ysp_forcepc，需要到所有适配包进行匹配，如果匹配到适配方案会打开一个新的WebView加载适配，如果没有匹配到
         * 则会直接用一个WebView加载这个url，还是一个pc版的。
         * <p>
         * 客户可以自己处理这个事件，如果返回true，则sdk不会打开一个新的WebView，返回false，默认处理会打开一个新的WebView加载。
         * <p>
         * 该方法只会在openWindow方法被适配js调用，并且url没有_ysp_forcepc参数，并且正则没有匹配到的时候。
         *
         * @param url openWidow返回的url
         * @return true：自己处理这个url，不会打开WebView加载它    false：默认处理，系统会打开一个WebView加载非适配url
         */
        boolean shouldHandleNoMatcherUrlFromOpenWindow(String url);

        /**
         * 是否拦截WebView的shouldOverrideUrlLoading方法，默认自己处理，可选择自己处理还是交给sdk处理。
         * 该方法用于适配Seibel系统：
         * Seibel系统的特点是：原网站只能在一个WebView中加载，用不同WebView加载会话过期，导致不可用，普天CRM系统是这样的
         *
         * @param view 当前WebView
         * @param url  加载的url
         * @return true：拦截该url自己处理，则network不会在加载其他请求     false：不处理，sdk自己处理
         */
        boolean shouldInterceptWebViewShouldOverrideUrlLoadingMethod(XWalkView view, String url);

        /**
         * 获取密码代填的配置信息,该方法在子线程执行
         */
        AutoLoginModel getAutoLoginModel(String url);

        void filePreviewConvertResult(String url);

        boolean showAdapterLoading(String message);

        boolean hideAdapterLoading();
    }

    public static class Builder {

        protected Bundle bundle;

        public Builder() {
            this.bundle = new Bundle();
        }

        /**
         * 设置当前tab要打开的链接，一般为原网站的链接
         *
         * @param url 链接
         */
        public Builder setUrl(@NonNull String url) {
            bundle.putString(ARGS_START_URL, url);
            return this;
        }

        /**
         * 如果链接是enterplorer协议，需要设置该协议的二级菜单的内容，因为EnterManager要控制二级菜单的权限，
         * 但是二级菜单又是适配包的资源展示的。原理：用户上传适配包的时候，EnterManager解析适配包下的config.json，该配置文件
         * 即是二级菜单的内容，客户端登录的时候manager会返回给我们当前用户二级列表的内容，通过这个地方传进去，适配页面通过yspUser对象调用
         * 原生方法返回给他们。
         */
        public Builder setAppMenu(String appMenu) {
            bundle.putString(ARGS_APP_MENU, appMenu);
            return this;
        }

        /**
         * 二维码扫码功能，二维码扫码，如果扫描的是EnterStudio的二维码，则会将适配包的资源替换指向EnterStudio上的资源
         */
        public Builder setDeveloperAppModel(DeveloperAppModel developerAppModel) {
            bundle.putParcelable(ARGS_DEVELOP_APP_MODEL, developerAppModel);
            return this;
        }

        /**
         * 是否默认支持双WebView，提供给Enterplorer的功能，适配开发组要求在客户端上可以手动关闭双WebView功能，如果该值为false
         * 则该Tab的适配应用不适用双WebView。
         * 默认值为true
         */
        public Builder setDefault2WebView(boolean isDefault2WebView) {
            bundle.putBoolean(ARGS_DEFAULT_SUPPORT_TWO_WEB_VIEW, isDefault2WebView);
            return this;
        }

        /**
         * 是否开启debug模式，默认不开启。
         * 如果开启debug模式，则适配页面会显示debug标志，可以看到适配的某些信息或内容。
         */
        public Builder setDebugMode(boolean debugMode) {
            bundle.putBoolean(ARGS_DEBUG_MODEL, debugMode);
            return this;
        }

        /**
         * 设置全局运行时版本，默认不设置。
         * 如果设置了全局运行时，则当前Tab的适配应用默认会使用设置的这个运行时版本。
         * 不设置默认会使用适配包中指定的运行时版本。
         */
        public Builder setGlobalRuntime(String runtimeVersion) {
            bundle.putString(ARGS_GLOBAL_RT, runtimeVersion);
            return this;
        }

        /**
         * 设置当前Tab要加载的资源的cookie，设置原理其实就是设置WebView的cookie方式。
         * 应用场景一般是企业内部有传统的SSO，通过cookie的形式实现系统的SSO。
         */
        public Builder setCookies(ArrayList<CookieModel> cookies) {
            bundle.putParcelableArrayList(ARGS_COOKIE_ARRAY_LIST, cookies);
            return this;
        }

        /**
         * 是否始终支持密码代填自动登录，默认不设置的话是不支持的，一个Tab只会十分钟密码代填一次。
         * ps：因为密码代填是将用户名密码填到输入框，然后点登陆，对用户来说不需要手动输入。因为登录后不知道是否登录成功，
         * 如果不做时间限制，一个页面出错了，则会一直代填下去。
         * <p>
         * 但是某些场景下又需要始终代填以达到和传统SSO一样的效果。如果用户app一定能给你正确的用户名密码，那他们肯定需要一直代填，而不是
         * 一个tab十分钟只代填一次。
         */
        public Builder setAlwaysAutoLogin(boolean alwaysAutoLogin) {
            bundle.putBoolean(ARGS_ALWAYS_AUTO_LOGIN, alwaysAutoLogin);
            return this;
        }

        /**
         * 设置水印功能，水印只显示在tab上。
         * 默认不设置则不显示，水印配置项可以参看SDK集成文档。
         */
        public Builder setWaterMark(WaterMarkConfig waterMarkConfig) {
            bundle.putParcelable(ARGS_WATER_MARK_CONFIG, waterMarkConfig);
            return this;
        }

        /**
         * 设置文档预览服务器地址。
         * SDK默认支持文档使用永中服务器转换，永中服务器是需要花钱购买的。传入转换服务器转换的url，则所有文档会采用预览的方式查看。
         * <p>
         * 如果不传入，则会下载，使用本地应用打开。
         * ps：如果直接下载使用本地应用打开，则需要注册YspDownload这个Service
         */
        public Builder setFilePreview(FilePreviewConfig filePreviewConfig) {
            bundle.putParcelable(ARGS_FILE_PREVIEW_CONFIG, filePreviewConfig);
            return this;
        }

        /**
         * 设置tab页面字体大小。
         */
        public Builder setTextZoom(int zoom) {
            bundle.putInt(ARGS_WEB_VIEW_TEXT_ZOOM, zoom);
            return this;
        }

        /**
         * 设置tab的ad认证的信息。
         * 因为crosswalk的下载默认采用的DownloadManager下载，不支持设置代理和401，403这种认证，所以下载需要自己去实现，好在
         * OKHttp比较强大，支持proxy，401，403认证，html通过webview加载，如果碰到这种认证会默认弹窗让你输入认证的用户名密码，
         * 但是这只是让WebView通过认证，自己用OKHttp，或者系统的URLConnection下载，这个认证还是需要自己去实现，所以如果用户集成
         * 我们的SDK需要通过这种认证，则需要传递给我认证的相关信息。
         */
        public Builder setHttpAuthorizations(ArrayList<HttpAuthModel> httpAuthModels) {
            bundle.putParcelableArrayList(ARGS_HTTP_AUTHORIZATIONS, httpAuthModels);
            return this;
        }

        //给每个加载的url加参数作为单点登录
        public Builder setUrlTokenSSO(ArrayList<UrlTokenSSOModel> urlTokenSSOs) {
            bundle.putParcelableArrayList(ARGS_URL_TOKEN_MODE_SSOS, urlTokenSSOs);
            return this;
        }

        public Builder setRequestHeaderSSO(ArrayList<RequestHeaderSSOModel> requestHeaderSSOModel) {
            bundle.putParcelableArrayList(ARGS_REQUEST_HEADERS_MODE_SSOS, requestHeaderSSOModel);
            return this;
        }

        public TabFragment build() {
            TabFragment tabFragment = new TabFragment();
            tabFragment.setArguments(bundle);
            return tabFragment;
        }
    }
}
